home *** CD-ROM | disk | FTP | other *** search
/ Power DOS 1996 July / Power DOS - July 1996.iso / sound / c_labs / devinfo / autoinit.exe / DMAW / DMAW.C next >
Encoding:
C/C++ Source or Header  |  1996-02-09  |  30.4 KB  |  996 lines

  1. /****************************************************************************
  2. *                                                                           *
  3. *  (C) Copyright Creative Technology Ltd. 1994-1996. All rights reserved.   *
  4. *                                                                           *
  5. *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY    *
  6. *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE      *
  7. *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR    *
  8. *  PURPOSE.                                                                 *
  9. *                                                                           *
  10. * You have a royalty-free right to use, modify, reproduce and               *
  11. * distribute the Sample Files (and/or any modified version) in              *
  12. * any way you find useful, provided that you agree that                     *
  13. * Creative has no warranty obligations or liability for any Sample Files.   *
  14. *                                                                           *
  15. ****************************************************************************/
  16.  
  17. /*************************************************************************
  18. *
  19. *  FILE : DMAW.C  ver 1.01
  20. *
  21. *  DMA DEMO PROGRAM FOR PLAYING WAVE FILES
  22. *
  23. *  PURPOSE:     This program demonstrates how to play a .wav file
  24. *               using DMA auto-init mode.
  25. *
  26. *  LIMITATION : This program does not support 8 bit STEREO for SBPro.
  27. *
  28. *               16 bit files must use the SB16.
  29. *
  30. *  DISCLAIMER : Although this program has been tested with
  31. *               standard 8/16 bit PCM WAVE files, there could
  32. *               exist some unknown bugs.
  33. *
  34. **************************************************************************/
  35. #include <conio.h>
  36. #include <dos.h>
  37. #include <mem.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40.  
  41.  
  42. #define DMA_BUF_SIZE    8192
  43. #define DMA8_FF_REG      0xC
  44. #define DMA8_MASK_REG    0xA
  45. #define DMA8_MODE_REG    0xB
  46. #define DMA16_FF_REG    0xD8
  47. #define DMA16_MASK_REG  0xD4
  48. #define DMA16_MODE_REG  0xD6
  49.  
  50. #define DMA0_ADDR        0
  51. #define DMA0_COUNT       1
  52. #define DMA0_PAGE     0x87
  53. #define DMA1_ADDR        2
  54. #define DMA1_COUNT       3
  55. #define DMA1_PAGE     0x83
  56. #define DMA3_ADDR        6
  57. #define DMA3_COUNT       7
  58. #define DMA3_PAGE     0x82
  59. #define DMA5_ADDR     0xC4
  60. #define DMA5_COUNT    0xC6
  61. #define DMA5_PAGE     0x8B
  62. #define DMA6_ADDR     0xC8
  63. #define DMA6_COUNT    0xCA
  64. #define DMA6_PAGE     0x89
  65. #define DMA7_ADDR     0xCC
  66. #define DMA7_COUNT    0xCE
  67. #define DMA7_PAGE     0x8A
  68.  
  69. #define DSP_BLOCK_SIZE            0x0048
  70. #define DSP_DATA_AVAIL               0xE
  71. #define DSP_HALT_SINGLE_CYCLE_DMA 0x00D0
  72. #define DSP_READ_PORT                0xA
  73. #define DSP_READY                   0xAA
  74. #define DSP_RESET                    0x6
  75. #define DSP_TIME_CONSTANT         0x0040
  76. #define DSP_WRITE_PORT               0xC
  77. #define DSP_VERSION                    0xE1
  78.  
  79. #define AUTO_INIT                   1
  80. #define FAIL                        0
  81. #define FALSE                       0
  82. #define MASTER_VOLUME            0x22
  83. #define MIC_VOLUME               0x0A
  84. #define MIXER_ADDR                0x4
  85. #define MIXER_DATA                0x5
  86. #define MONO                        0
  87. #define PIC_END_OF_INT           0x20
  88. #define PIC_MASK                 0x21
  89. #define PIC_MODE                 0x20
  90. #define SUCCESS                     1
  91. #define SINGLE_CYCLE                0
  92. #define STEREO                      1
  93. #define TRUE                        1
  94. #define VOICE_VOLUME             0x04
  95.  
  96. struct WAVEHDR{
  97.     char             format[4];      // RIFF
  98.     unsigned long     f_len;          // filelength
  99.     char            wave_fmt[8];    // WAVEfmt_
  100.     unsigned long    fmt_len;    // format lenght
  101.     unsigned short  fmt_tag;    // format Tag
  102.     unsigned short  channel;    // Mono/Stereo
  103.     unsigned long   samples_per_sec;
  104.     unsigned long   avg_bytes_per_sec;
  105.     unsigned short  blk_align;
  106.     unsigned short  bits_per_sample;
  107.     char            data[4];        // data
  108.     unsigned long   data_len;    // data size
  109.     } wavehdr;
  110.  
  111.  
  112. /*---------  FUNCTION PROTOTYPES  --------------------------------*/
  113. /*----------------------------------------------------------------*/
  114. char           GetBlasterEnv(int *, int *, int *),
  115.                InitDMADSP(unsigned long, int, int),
  116.                ResetDSP(int);
  117.  
  118. unsigned int   FillHalfOfBuffer(int *, FILE *, unsigned char *);
  119.  
  120. unsigned long  AllocateDMABuffer(unsigned char **),
  121.                OnSamePage(unsigned char *);
  122.  
  123. void           Play(unsigned int, char),
  124.                DSPOut(int, int),
  125.                Fill_play_buf(unsigned char *, int *, FILE *),
  126.                SetMixer(void);
  127.  
  128. void interrupt DMAOutputISR(void);   // Interrupt Service Routine
  129.  
  130. int                  Chk_hdr(void);
  131. /*----------------------------------------------------------------*/
  132.  
  133. /*---------  GLOBAL DECLARATIONS  --------------------------------*/
  134. /*----------------------------------------------------------------*/
  135. char  gBufNowPlaying,
  136.       gEndOfFile,
  137.       gLastBufferDonePlaying,
  138.       Mode,      // indicates MONO or STEREO
  139.       g16BitDMA;
  140.  
  141. int   Base,
  142.       DSP_Ver;
  143.  
  144. unsigned long gNoOfBytesLeftInFile;
  145.  
  146. /*----------------------------------------------------------------*/
  147.  
  148.  
  149. /*--- BEGIN main() -----------------------------------------------*/
  150. /*----------------------------------------------------------------*/
  151. int main(int argv, char *argc[])
  152. {
  153.   char  Filename[80],
  154.     Filetype[44],
  155.     RetValue;
  156.  
  157.   FILE *FileToPlay;
  158.  
  159.   int BufToFill,
  160.       DMAChan8Bit,
  161.       DMAChan16Bit,
  162.       IRQNumber,
  163.       IRQMask,
  164.       MaskSave,
  165.       Offset;
  166.  
  167.   unsigned char *DMABuffer;
  168.   unsigned int   BytesLeftToPlay;
  169.   unsigned long  BufPhysAddr;
  170.  
  171.   void interrupt (*IRQSave)(void);
  172.  
  173.   /*--- OPEN FILE TO BE PLAYED -------------------------------*/
  174.   /*----------------------------------------------------------*/
  175.   if (argv > 1)
  176.   {
  177.  
  178.       if ((FileToPlay = fopen(argc[1], "rb")) == NULL)
  179.       {
  180.       printf("%s Error opening file--PROGRAM TERMINATED!\n",
  181.         argc[1]);
  182.       exit(0);
  183.       }
  184.  
  185.   }
  186.   else
  187.   {
  188.      printf("\nDMAW version 1.01");
  189.      printf("\nUsage : DMAW WAV-file\n");
  190.      exit(0);
  191.   }
  192.  
  193.   clrscr();
  194.   printf("\tDMA program for playing .WAV files");
  195.   printf("\n\t----------------------------------\n\n");
  196.   /*--- VERIFY FILE IS .WAV FORMAT---------------------------*/
  197.   /*---------------------------------------------------------*/
  198.   memset (&wavehdr,0,sizeof(wavehdr));  //init to 0
  199.  
  200.   fread(&wavehdr, 44, 1, FileToPlay);  // Get file type description.
  201.   if(Chk_hdr())
  202.   {
  203.      printf("Header check error - PROGRAM ABORTED");
  204.      exit(0);
  205.   }
  206.  
  207.   Mode = (wavehdr.channel == 1) ? MONO : STEREO;
  208.  
  209.   /*--- ALLOCATE BUFFERS -----------------------------------------*/
  210.   /*--------------------------------------------------------------*/
  211.   BufPhysAddr = AllocateDMABuffer(&DMABuffer);
  212.   if (BufPhysAddr == FAIL)
  213.   {
  214.     puts("DMA Buffer allocation failed!--PROGRAM ABORTED");
  215.     fclose(FileToPlay);
  216.     exit(0);
  217.   }
  218.  
  219.  
  220.   /*--- GET ENVIRONMENT VALUES -----------------------------------*/
  221.   /*--------------------------------------------------------------*/
  222.   RetValue = GetBlasterEnv(&DMAChan8Bit, &DMAChan16Bit, &IRQNumber);
  223.  
  224.   /*--- PRINT OUT INFO -------------------------------------------*/
  225.   /*--------------------------------------------------------------*/
  226.   printf("    DMA Buffer Address     = %4x:%-4x (SEG:OFF) (hex)\n",
  227.      FP_SEG(DMABuffer), FP_OFF(DMABuffer));
  228.   printf("    DMA Buffer Phys. Addr. = %-7lu   (decimal)\n",  BufPhysAddr);
  229.   printf("    8-bit DMA channel      = %-5d     (decimal)\n",   DMAChan8Bit);
  230.   printf("    16-bit DMA channel     = %-5d     (decimal)\n",   DMAChan16Bit);
  231.   printf("    I/O port address       = %-3x       (hex)\n",       Base);
  232.   printf("    IRQ number             = %-2d        (decimal)\n\n", IRQNumber);
  233.  
  234.  
  235.   /*--- ARE ENVIRONMENT VALUES VALID? --------------------------*/
  236.   /*------------------------------------------------------------*/
  237.   if (RetValue == FAIL)
  238.   {
  239.     puts("BLASTER env. string or parameter(s) missing--PROGRAM ABORTED!");
  240.     free(DMABuffer);
  241.     fclose(FileToPlay);
  242.     exit(0);
  243.   }
  244.  
  245.   /*--- RESET THE DSP ----------------------------------------*/
  246.   /*----------------------------------------------------------*/
  247.   if(ResetDSP(Base) == FAIL)
  248.   {
  249.     puts("Unable to reset DSP chip--PROGRAM TERMINATED!");
  250.     free(DMABuffer);
  251.     fclose(FileToPlay);
  252.     exit(0);
  253.   }
  254.  
  255.   if((DSP_Ver < 4) && (wavehdr.bits_per_sample == 16))
  256.   {
  257.     printf("\n** DSP version %d.xx does not support 16bit files.\n", DSP_Ver);
  258.     free(DMABuffer);
  259.     fclose(FileToPlay);
  260.     exit(0);
  261.   }
  262.  
  263.  
  264.   /*--- SAVE CURRENT ISR FOR IRQNumber, THEN GIVE IRQNumber NEW ISR ---*/
  265.   /*-------------------------------------------------------------------*/
  266.   IRQSave = getvect(IRQNumber + 8);
  267.   setvect(IRQNumber + 8, DMAOutputISR);
  268.  
  269.  
  270.   /*--- SAVE CURRENT INTERRUPT MASK AND SET NEW INTERRUPT MASK -------*/
  271.   /*------------------------------------------------------------------*/
  272.   MaskSave = inp((int) PIC_MASK);
  273.   IRQMask = ((int) 1 << IRQNumber); // Shift a 1 left IRQNumber of bits
  274.   outp(PIC_MASK, (MaskSave & ~IRQMask)); // Enable previous AND new interrupts
  275.  
  276.  
  277.   /*--- PROGRAM THE DMA, DSP CHIPS -----------------------------------*/
  278.   /*------------------------------------------------------------------*/
  279.   if (InitDMADSP(BufPhysAddr, DMAChan8Bit, DMAChan16Bit) == FAIL)
  280.   {
  281.     puts("InitDMADSP() fails--PROGRAM ABORTED!");
  282.     free(DMABuffer);
  283.     fclose(FileToPlay);
  284.     exit(0);
  285.   }
  286.  
  287.  
  288.   /*--- FILL THE FIRST 1/2 OF DMA BUFFER BEFORE PLAYING BEGINS -------*/
  289.   /*------------------------------------------------------------------*/
  290.   BufToFill              = 0;      // Altered by FillHalfOfBuffer()
  291.   gEndOfFile             = FALSE;  // Altered by FillHalfOfBuffer()
  292.   gBufNowPlaying         = 0;      // Altered by ISR
  293.   gLastBufferDonePlaying = FALSE;  // Set in ISR
  294.   gNoOfBytesLeftInFile     = wavehdr.data_len;
  295.   SetMixer();
  296.  
  297.   BytesLeftToPlay = FillHalfOfBuffer(&BufToFill, FileToPlay, DMABuffer);
  298.  
  299.   /*--- BEGIN PLAYING THE FILE ---------------------------------------*/
  300.   /*------------------------------------------------------------------*/
  301.   if (wavehdr.data_len < DMA_BUF_SIZE / 2)  // File size is < 1/2 buffer size.
  302.   {
  303.     Play(BytesLeftToPlay, SINGLE_CYCLE);
  304.     while (gBufNowPlaying == 0);  // Wait for playing to finish (ISR called)
  305.   }
  306.   else  // File size >= 1/2 buffer size
  307.   {
  308.     Play(BytesLeftToPlay, AUTO_INIT);
  309.     Fill_play_buf(DMABuffer, &BufToFill, FileToPlay);
  310.   }
  311.  
  312.   DSPOut(Base, DSP_HALT_SINGLE_CYCLE_DMA);  // Done playing, halt DMA
  313.  
  314.  
  315.   /*--- RESTORE ISR AND ORIGINAL IRQ VECTOR -------------------------*/
  316.   /*-----------------------------------------------------------------*/
  317.   outp(PIC_MASK, MaskSave);
  318.   setvect(IRQNumber + 8, IRQSave);
  319.  
  320.   free(DMABuffer);
  321.   fclose(FileToPlay);
  322.   return(0);
  323. }
  324.  
  325.  
  326. /**********************************************************************
  327. *
  328. * FUNCTION : Chk_hdr()
  329. *
  330. * DESCRIPTION : check for validity of the wave file header
  331. *
  332. ************************************************************************/
  333.  
  334. int Chk_hdr()
  335. {
  336.   if (memcmp(wavehdr.format, "RIFF", 4))
  337.   {
  338.     puts("File is not a valid .WAV file--PROGRAM ABORTED");
  339.     return 1;
  340.   }
  341.  
  342.   if (memcmp(wavehdr.wave_fmt, "WAVEfmt ", 8))
  343.   {
  344.     puts("File is not a valid .WAV file");
  345.     return 1;
  346.   }
  347.  
  348.   if (!((wavehdr.channel == 1) || (wavehdr.channel == 2)))
  349.   {
  350.      printf("Unknown number of channels -> %d", wavehdr.channel);
  351.      return 1;
  352.   }
  353.  
  354.   return 0;
  355. } /* chk_hdr() */
  356.  
  357.  
  358. /*************************************************************************
  359. *
  360. *  FUNCTION: Play()
  361. *
  362. *  DESCRIPTION : Sets up playing of the wave file depending on number
  363. *         of bits per sample, MONO/STEREO and DMAMode
  364. *
  365. *************************************************************************/
  366. void Play(unsigned int BytesLeftToPlay, char DMAMode)
  367. {
  368.   int Command;
  369.  
  370.   /*--- IF BytesLeftToPlay IS 0 OR 1, MAKE SURE THAT WHEN DSPOut() IS ---*/
  371.   /*--- CALLED, THE COUNT DOESN'T WRAP AROUND TO A + NUMBER WHEN 1 IS ---*/
  372.   /*    SUBTRACTED! -----------------------------------------------------*/
  373.   if(BytesLeftToPlay <= 1 && g16BitDMA)
  374.     BytesLeftToPlay = 2;
  375.   else if (BytesLeftToPlay == 0 && !g16BitDMA)
  376.     BytesLeftToPlay = 1;
  377.  
  378.   if(DSP_Ver < 4) // SBPro (DSP ver 3.xx)
  379.   {
  380.     if(wavehdr.bits_per_sample == 8)
  381.     {
  382.       if (DMAMode == AUTO_INIT)
  383.       {
  384.         DSPOut(Base, DSP_BLOCK_SIZE);
  385.         DSPOut(Base, (int) ((BytesLeftToPlay - 1) & 0x00FF));
  386.         DSPOut(Base, (int) ((BytesLeftToPlay - 1) >> 8));
  387.         DSPOut(Base, 0x001C);  // AUTO INIT 8bit PCM
  388.       }
  389.       else
  390.       {
  391.         DSPOut(Base, 0x0014);  // SINGLE CYCLE 8bit PCM
  392.         DSPOut(Base, (BytesLeftToPlay - 1) & 0x00FF);  // LO byte size
  393.         DSPOut(Base, (BytesLeftToPlay - 1) >> 8);       // HI byte size
  394.       }
  395.     }
  396.     else if (wavehdr.bits_per_sample == 16) // 16Bit
  397.     {
  398.       DSPOut(Base, 0x0041);
  399.       DSPOut(Base, (int) ((wavehdr.samples_per_sec & 0x0000FF00) >> 8));
  400.       DSPOut(Base, (int) (wavehdr.samples_per_sec & 0x000000FF));
  401.       DSPOut(Base, (DMAMode == AUTO_INIT) ? 0x00B4 : 0x00B0); // AUTO INIT/SINGLE CYCLE
  402.       DSPOut(Base, (Mode == MONO) ? 0x0010 : 0x0030);  // MONO/STEREO
  403.       DSPOut(Base, (BytesLeftToPlay/2 - 1) & 0x00FF);     // LO byte size
  404.       DSPOut(Base, (BytesLeftToPlay/2 - 1) >> 8);         // HI byte size
  405.     }
  406.   }
  407.   else if(DSP_Ver == 4)// SB16 (DSP ver 4.xx)
  408.   {
  409.     DSPOut(Base, 0x0041);  // DSP output transfer rate
  410.     DSPOut(Base, (int) ((wavehdr.samples_per_sec & 0x0000FF00) >> 8)); // Hi byte
  411.     DSPOut(Base, (int) (wavehdr.samples_per_sec & 0x000000FF));        // Lo byte
  412.  
  413.     if (DMAMode == AUTO_INIT)
  414.       DSPOut(Base, (wavehdr.bits_per_sample == 8) ? 0x00C6 : 0x00B6);  // AUTO INIT 8/16 bit
  415.     else
  416.       DSPOut(Base, (wavehdr.bits_per_sample == 8) ? 0x00C0 : 0x00B0);  // SINGLE CYCLE 8/16 bit
  417.  
  418.     if (wavehdr.bits_per_sample == 8)
  419.       DSPOut(Base, (Mode == MONO) ? 0x0000 : 0x0020); // 8bit MONO/STEREO
  420.     else
  421.       DSPOut(Base, (Mode == MONO) ? 0x0010 : 0x0030); // 16bit MONO/STEREO
  422.  
  423.   /*--- Program number of samples to play -------------------------------*/
  424.     DSPOut(Base, (int) ((BytesLeftToPlay/(wavehdr.bits_per_sample/8) - 1) & 0x00FF)); // LO byte
  425.     DSPOut(Base, (int) ((BytesLeftToPlay/(wavehdr.bits_per_sample/8) - 1) >> 8));     // HI byte
  426.   }
  427.  
  428.   return;
  429. }
  430.  
  431. /*************************************************************************
  432. *
  433. * FUNCTION: Fill_play_buf()
  434. *
  435. * DESCRIPTION : Keeps the DMA buffers filled with new data until end of
  436. *        file.
  437. *
  438. *************************************************************************/
  439. void Fill_play_buf(unsigned char *DMABuffer, int *BufToFill, FILE *FileToPlay)
  440. {
  441.   unsigned int NumberOfAudioBytesInBuffer, Count;
  442.  
  443.   do
  444.   {
  445.     while (*BufToFill == gBufNowPlaying); // Wait for buffer to finish playing
  446.  
  447.     NumberOfAudioBytesInBuffer = FillHalfOfBuffer(BufToFill, FileToPlay,
  448.                           DMABuffer);
  449.     if (NumberOfAudioBytesInBuffer < DMA_BUF_SIZE / 2)
  450.       Play(NumberOfAudioBytesInBuffer, SINGLE_CYCLE);
  451.  
  452.   } while (!gEndOfFile);  // gEndOfFile set in FillHalfOfBuffer()
  453.  
  454.   while (gLastBufferDonePlaying == FALSE);  // Wait until done playing
  455.  
  456.   return;
  457. }
  458.  
  459. /*************************************************************************
  460. *
  461. * FUNCTION: FillHalfOfBuffer()
  462. *
  463. * DESCRIPTION : Fill each half of the DMA buffer.
  464. *
  465. *************************************************************************/
  466. unsigned int FillHalfOfBuffer(int *BufToFill, FILE *FileToPlay,
  467.                   unsigned char *DMABuffer)
  468. {
  469.   unsigned int Count;
  470.  
  471.   if (*BufToFill == 1)  // Fill top 1/2 of DMA buffer
  472.     DMABuffer += DMA_BUF_SIZE / 2;
  473.  
  474.   if(gNoOfBytesLeftInFile < DMA_BUF_SIZE/2)
  475.   {
  476.      fread(DMABuffer, gNoOfBytesLeftInFile, 1, FileToPlay);
  477.      Count = gNoOfBytesLeftInFile;
  478.      gNoOfBytesLeftInFile = 0;
  479.      gEndOfFile = TRUE;
  480.   }
  481.   else
  482.   {
  483.      fread(DMABuffer, DMA_BUF_SIZE/2, 1, FileToPlay);
  484.      Count = DMA_BUF_SIZE/2;
  485.      gNoOfBytesLeftInFile -= DMA_BUF_SIZE/2;
  486.   }
  487.  
  488.  
  489.   *BufToFill ^= 1;  // Toggle to fill other 1/2 of buffer next time.
  490.  
  491.   return(Count);
  492. }
  493.  
  494. /*************************************************************************
  495. *
  496. * FUNCTION: DMAOutputISR()
  497. *
  498. * DESCRIPTION:  Interrupt service routine.  Every time the DSP chip finishes
  499. *               playing half of the DMA buffer in auto-init mode, an
  500. *               interrupt is generated, which invokes this routine.
  501. *
  502. *************************************************************************/
  503. void interrupt DMAOutputISR(void)
  504. {
  505.   static char SecondToLastBufferPlayed = FALSE;
  506.   int IntStatus;
  507.  
  508.   if (g16BitDMA == TRUE)
  509.   {
  510.     outp(Base + 4, 0x82);       // Select interrupt status reg. in mixer
  511.     IntStatus = inp(Base + 5);  // Read interrupt status reg.
  512.  
  513.     if (IntStatus & 2)
  514.       inp(Base + 0xF);   // Acknowledge interrupt (16-bit)
  515.   }
  516.   else
  517.     inp(Base + (int) DSP_DATA_AVAIL);  // Acknowledge interrupt (8-bit)
  518.  
  519.   gBufNowPlaying ^= 1;
  520.  
  521.   outp(PIC_MODE, (int) PIC_END_OF_INT); // End of interrupt
  522.  
  523.   if (SecondToLastBufferPlayed)
  524.     gLastBufferDonePlaying = TRUE;
  525.  
  526.   if (gEndOfFile)
  527.     SecondToLastBufferPlayed = TRUE;
  528.  
  529.   return;
  530. }
  531.  
  532.  
  533. /*************************************************************************
  534. *
  535. * FUNCTION: InitDMADSP()
  536. *
  537. * DESCRIPTION: This function reads the first data block of the file and
  538. *              from it obtains information that is needed to program the
  539. *              DMA and DSP chips.  After reading the data block, the file
  540. *              pointer points to the first byte of the voice data.
  541. *
  542. *              NOTE: The DMA chip is ALWAYS programmed for auto-init mode
  543. *                    (command 0x58)!  The DSP chip will be programmed for
  544. *                    auto-init or single-cycle mode depending upon
  545. *                    conditions--see Play() for details.
  546. *
  547. *************************************************************************/
  548. char InitDMADSP(unsigned long BufPhysAddr, int DMAChan8Bit, int DMAChan16Bit)
  549. {
  550.   char BitsPerSample,
  551.        BlockType,
  552.        Pack;
  553.  
  554.   int  DMAAddr,
  555.        DMACount,
  556.        DMAPage,
  557.        Offset,
  558.        Page,
  559.        Temp;
  560.  
  561.   unsigned char ByteTimeConstant;
  562.   unsigned int  WordTimeConstant;
  563.  
  564.  
  565.   /*--- GET DMA ADDR., COUNT, AND PAGE FOR THE DMA CHANNEL USED ----------*/
  566.   /*----------------------------------------------------------------------*/
  567.   if (wavehdr.bits_per_sample == 8)
  568.   {
  569.     g16BitDMA = FALSE; // DMA is not 16-bit (it's 8-bit).
  570.  
  571.     switch(DMAChan8Bit)   // File is 8-bit.  Program DMA 8-bit DMA channel
  572.     {
  573.       case 0:
  574.     DMAAddr  = DMA0_ADDR;
  575.     DMACount = DMA0_COUNT;
  576.     DMAPage  = DMA0_PAGE;
  577.       break;
  578.  
  579.       case 1:
  580.     DMAAddr  = DMA1_ADDR;
  581.     DMACount = DMA1_COUNT;
  582.     DMAPage  = DMA1_PAGE;
  583.       break;
  584.  
  585.       case 3:
  586.     DMAAddr  = DMA3_ADDR;
  587.     DMACount = DMA3_COUNT;
  588.     DMAPage  = DMA3_PAGE;
  589.       break;
  590.  
  591.       default:
  592.     puts("File is 8-bit--invalid 8-bit DMA channel");
  593.       return(FAIL);
  594.     }
  595.   }
  596.   else
  597.   {
  598.     g16BitDMA = TRUE;     // DMA is 16-bit (not 8-bit).
  599.  
  600.     switch(DMAChan16Bit)  // File is 16-bit.  Program DMA 16-bit DMA channel
  601.     {
  602.       case 5:
  603.     DMAAddr  = DMA5_ADDR;
  604.     DMACount = DMA5_COUNT;
  605.     DMAPage  = DMA5_PAGE;
  606.       break;
  607.  
  608.       case 6:
  609.     DMAAddr  = DMA6_ADDR;
  610.     DMACount = DMA6_COUNT;
  611.     DMAPage  = DMA6_PAGE;
  612.       break;
  613.  
  614.       case 7:
  615.     DMAAddr  = DMA7_ADDR;
  616.     DMACount = DMA7_COUNT;
  617.     DMAPage  = DMA7_PAGE;
  618.       break;
  619.  
  620.       default:
  621.     puts("File is 16-bit--invalid 16-bit DMA channel");
  622.       return(FAIL);
  623.     }
  624.  
  625.     DMAChan16Bit -= 4; // Convert
  626.   }
  627.  
  628.  
  629.   /*--- PROGRAM THE DMA CHIP ---------------------------------------------*/
  630.   /*----------------------------------------------------------------------*/
  631.   Page   = (int) (BufPhysAddr >> 16);
  632.   Offset = (int) (BufPhysAddr & 0xFFFF);
  633.  
  634.   if (wavehdr.bits_per_sample == 8) // 8-bit file--Program 8-bit DMA controller
  635.   {
  636.     outp(DMA8_MASK_REG, (int) (DMAChan8Bit | 4));     // Disable DMA while prog.
  637.     outp(DMA8_FF_REG,   (int) 0);                     // Clear the flip-flop
  638.  
  639.     outp(DMA8_MODE_REG, (int) (DMAChan8Bit  | 0x58));  // 8-bit auto-init
  640.     outp(DMACount, (int) ((DMA_BUF_SIZE - 1) & 0xFF)); // LO byte of count
  641.     outp(DMACount, (int) ((DMA_BUF_SIZE - 1) >> 8));   // HI byte of count
  642.   }
  643.   else    // 16-bit file--Program 16-bit DMA controller
  644.   {
  645.     // Offset for 16-bit DMA channel must be calculated differently...
  646.     // Shift Offset 1 bit right, then copy LSB of Page to MSB of Offset.
  647.     Temp = Page & 0x0001;  // Get LSB of Page and...
  648.     Temp <<= 15;           // ...move it to MSB of Temp.
  649.     Offset >>= 1;          // Divide Offset by 2
  650.     Offset &= 0x7FFF;      // Clear MSB of Offset
  651.     Offset |= Temp;        // Put LSB of Page into MSB of Offset
  652.  
  653.     outp(DMA16_MASK_REG, (int) (DMAChan16Bit | 4));    // Disable DMA while prog.
  654.     outp(DMA16_FF_REG,   (int) 0);                     // Clear the flip-flop
  655.  
  656.     outp(DMA16_MODE_REG, (int) (DMAChan16Bit  | 0x58));  // 16-bit auto-init
  657.     outp(DMACount, (int) ((DMA_BUF_SIZE/2 - 1) & 0xFF)); // LO byte of count
  658.     outp(DMACount, (int) ((DMA_BUF_SIZE/2 - 1) >> 8));   // HI byte of count
  659.   }
  660.  
  661.  
  662.   outp(DMAPage, Page);                   // Physical page number
  663.   outp(DMAAddr, (int) (Offset & 0xFF));  // LO byte address of buffer
  664.   outp(DMAAddr, (int) (Offset >> 8));    // HI byte address of buffer
  665.  
  666.  
  667.   // Done programming the DMA, enable it
  668.   if (wavehdr.bits_per_sample == 8)
  669.     outp(DMA8_MASK_REG, DMAChan8Bit);
  670.   else
  671.     outp(DMA16_MASK_REG, DMAChan16Bit);
  672.  
  673.  
  674.   /*--- PROGRAM THE DSP CHIP ------------------------------------------*/
  675.   /*-------------------------------------------------------------------*/
  676.   if(DSP_Ver < 4)
  677.   {
  678.     ByteTimeConstant = (unsigned char) (256 - 1000000/wavehdr.samples_per_sec);
  679.     DSPOut(Base, (int) DSP_TIME_CONSTANT);
  680.     DSPOut(Base, (int) ByteTimeConstant);
  681.   }
  682.  
  683.   DSPOut(Base, 0x00D1);  // Must turn speaker ON before doing D/A conv.
  684.  
  685.   return(SUCCESS);
  686. }
  687.  
  688.  
  689. /*************************************************************************
  690. *
  691. * FUNCTION: AllocateDMABuffer()
  692. *
  693. * DESCRIPTION : Allocate memory for the DMA buffer.  After memory is
  694. *               allocated for the buffer, call OnSamePage() to verify
  695. *               that the entire buffer is located on the same page.
  696. *               If the buffer crosses a page boundary, allocate another
  697. *               buffer. Continue this process until the DMA buffer resides
  698. *               entirely within the same page.
  699. *
  700. * ENTRY: **DMABuffer is the address of the pointer that will point to
  701. *        the memory allocated.
  702. *
  703. * EXIT: If a buffer is succesfully allocated, *DMABuffer will point to
  704. *       the buffer and the physical address of the buffer pointer will
  705. *       be returned.
  706. *
  707. *       If a buffer is NOT successfully allocated, return FAIL.
  708. *
  709. *************************************************************************/
  710. unsigned long AllocateDMABuffer(unsigned char **DMABuffer)
  711. {
  712.   unsigned char  BufferNotAllocated = TRUE,
  713.          Done = FALSE,
  714.         *PtrAllocated[100];
  715.  
  716.   int            i,
  717.          Index = 0;
  718.  
  719.   unsigned long  PhysAddress;
  720.  
  721.   do
  722.   {
  723.     *DMABuffer = (unsigned char *) malloc(DMA_BUF_SIZE);
  724.  
  725.     if (*DMABuffer != NULL)
  726.     {
  727.       /*--- Save the ptr for every malloc() performed ---*/
  728.       PtrAllocated[Index] = *DMABuffer;
  729.       Index++;
  730.  
  731.       /*--- If entire buffer is within one page, we're out of here! ---*/
  732.       PhysAddress = OnSamePage(*DMABuffer);
  733.       if (PhysAddress != FAIL)
  734.       {
  735.     BufferNotAllocated = FALSE;
  736.     Done = TRUE;
  737.       }
  738.     }
  739.     else
  740.       Done = TRUE;  // malloc() couldn't supply requested memory
  741.  
  742.   } while (!Done);
  743.  
  744.  
  745.   if (BufferNotAllocated)
  746.   {
  747.     Index++;             // Incr. Index so most recent malloc() gets free()d
  748.     PhysAddress = FAIL;  // return FAIL
  749.   }
  750.  
  751.   /*--- Deallocate all memory blocks crossing a page boundary ---*/
  752.   for (i= 0; i < Index - 1; i++)
  753.     free(PtrAllocated[i]);
  754.  
  755.   return(PhysAddress);
  756. }
  757.  
  758.  
  759. /**************************************************************************
  760. *
  761. * FUNCTION: OnSamePage()
  762. *
  763. * DESCRIPTION: Check the memory block pointed to by the parameter
  764. *              passed to make sure the entire block of memory is on the
  765. *              same page.  If a buffer DOES cross a page boundary,
  766. *              return FAIL. Otherwise, return the physical address
  767. *              of the beginning of the DMA buffer.
  768. *
  769. * ENTRY: *DMABuffer - Points to beginning of DMA buffer.
  770. *
  771. * EXIT: If the buffer is located entirely within one page, return the
  772. *       physical address of the buffer pointer.  Otherwise return FAIL.
  773. *
  774. **************************************************************************/
  775. unsigned long OnSamePage(unsigned char *DMABuffer)
  776. {
  777.   unsigned long BegBuffer,
  778.         EndBuffer,
  779.         PhysAddress;
  780.  
  781.   /*----- Obtain the physical address of DMABuffer -----*/
  782.   BegBuffer = ((unsigned long) (FP_SEG(DMABuffer)) << 4) +
  783.            (unsigned long) FP_OFF(DMABuffer);
  784.   EndBuffer   = BegBuffer + DMA_BUF_SIZE - 1;
  785.   PhysAddress = BegBuffer;
  786.  
  787.   /*-- Get page numbers for start and end of DMA buffer. --*/
  788.   BegBuffer >>= 16;
  789.   EndBuffer >>= 16;
  790.  
  791.   if (BegBuffer == EndBuffer)
  792.     return(PhysAddress);  // Entire buffer IS on same page!
  793.   return(FAIL); // Entire buffer NOT on same page.  Thanks Intel!
  794. }
  795.  
  796.  
  797. /**************************************************************************
  798. *
  799. * FUNCTION: GetBlasterEnv()
  800. *
  801. * DESCRIPTION : Get the BLASTER environment variable and search its
  802. *               string for the DMA channel, I/O address port, and
  803. *               IRQ number.  Assign these values to the parameters passed
  804. *               by the caller.
  805. *
  806. * ENTRY: All parameters passed are pointers to integers.  They will be
  807. *        assigned the values found in the environment string.
  808. *
  809. * EXIT:  If DMA channel, I/O address, and IRQ number are found, return
  810. *        PASS, otherwise return FAIL.
  811. *
  812. *
  813. **************************************************************************/
  814. char GetBlasterEnv(int *DMAChan8Bit, int *DMAChan16Bit, int *IRQNumber)
  815. {
  816.   char  Buffer[5],
  817.     DMAChannelNotFound = TRUE,
  818.        *EnvString,
  819.     IOPortNotFound     = TRUE,
  820.     IRQNotFound        = TRUE,
  821.     SaveChar;
  822.  
  823.   int   digit,
  824.     i,
  825.     multiplier;
  826.  
  827.  
  828.   EnvString = getenv("BLASTER");
  829.  
  830.   if (EnvString == NULL)
  831.     return(FAIL);
  832.  
  833.   do
  834.   {
  835.     switch(*EnvString)
  836.     {
  837.       case 'A':  // I/O base port address found
  838.       case 'a':
  839.     EnvString++;
  840.     for (i = 0; i < 3; i++)  // Grab the digits
  841.     {
  842.       Buffer[i] = *EnvString;
  843.       EnvString++;
  844.     }
  845.  
  846.     // The string is in HEX, convert it to decimal
  847.     multiplier = 1;
  848.     Base = 0;
  849.     for (i -= 1; i >= 0; i--)
  850.     {
  851.       // Convert to HEX
  852.       if (Buffer[i] >= '0' && Buffer[i] <= '9')
  853.         digit = Buffer[i] - '0';
  854.       else if (Buffer[i] >= 'A' && Buffer[i] <= 'F')
  855.         digit = Buffer[i] - 'A' + 10;
  856.       else if (Buffer[i] >= 'a' && Buffer[i] <= 'f')
  857.         digit = Buffer[i] - 'a' + 10;
  858.  
  859.       Base = Base + digit * multiplier;
  860.       multiplier *= 16;
  861.     }
  862.  
  863.     IOPortNotFound = FALSE;
  864.       break;
  865.  
  866.  
  867.       case 'D': // 8-bit DMA channel
  868.       case 'd':
  869.       case 'H': // 16-bit DMA channel
  870.       case 'h':
  871.     SaveChar = *EnvString;
  872.     EnvString++;
  873.     Buffer[0] = *EnvString;
  874.     EnvString++;
  875.  
  876.     if (*EnvString >= '0' && *EnvString <= '9')
  877.     {
  878.       Buffer[1] = *EnvString; // DMA Channel No. is 2 digits
  879.       Buffer[2] = NULL;
  880.       EnvString++;
  881.     }
  882.     else
  883.       Buffer[1] = NULL;       // DMA Channel No. is 1 digit
  884.  
  885.     if (SaveChar == 'D' || SaveChar == 'd')
  886.       *DMAChan8Bit  = atoi(Buffer);  // 8-Bit DMA channel
  887.     else
  888.       *DMAChan16Bit = atoi(Buffer);  // 16-bit DMA channel
  889.  
  890.     DMAChannelNotFound = FALSE;
  891.       break;
  892.  
  893.       case 'I':  // IRQ number
  894.       case 'i':
  895.     EnvString++;
  896.     Buffer[0] = *EnvString;
  897.     EnvString++;
  898.  
  899.     if (*EnvString >= '0' && *EnvString <= '9')
  900.     {
  901.       Buffer[1] = *EnvString; // IRQ No. is 2 digits
  902.       Buffer[2] = NULL;
  903.       EnvString++;
  904.     }
  905.     else
  906.       Buffer[1] = NULL;       // IRQ No. is 1 digit
  907.  
  908.     *IRQNumber  = atoi(Buffer);
  909.     IRQNotFound = FALSE;
  910.       break;
  911.  
  912.       default:
  913.     EnvString++;
  914.       break;
  915.     }
  916.  
  917.   } while (*EnvString != NULL);
  918.  
  919.   if (DMAChannelNotFound || IOPortNotFound || IRQNotFound)
  920.     return(FAIL);
  921.  
  922.   return(SUCCESS);
  923. }
  924.  
  925.  
  926. /*************************************************************************
  927. *
  928. * FUNCTION: DSPOut()
  929. *
  930. * DESCRIPTION: Writes the value passed to this function to the DSP chip.
  931. *
  932. *************************************************************************/
  933. void DSPOut(int IOBasePort, int WriteValue)
  934. {
  935.   // Wait until DSP is ready before writing the command
  936.   while ((inp(IOBasePort + DSP_WRITE_PORT) & 0x80) != 0);
  937.  
  938.   outp(IOBasePort + DSP_WRITE_PORT, WriteValue);
  939.   return;
  940. }
  941.  
  942.  
  943. /*************************************************************************
  944. *
  945. * FUNCTION: ResetDSP()
  946. *
  947. * DESCRIPTION: Self explanatory
  948. *
  949. *************************************************************************/
  950. char ResetDSP(int IOBasePort)
  951. {
  952.   unsigned long i;
  953.  
  954.   outp(IOBasePort + DSP_RESET, (int) 1);
  955.   delay(10); // wait 10 mS
  956.   outp(IOBasePort + DSP_RESET, (int) 0);
  957.  
  958.   // Wait until data is available
  959.   while ((inp(IOBasePort + DSP_DATA_AVAIL) & 0x80) == 0);
  960.  
  961.   if (inp(IOBasePort + DSP_READ_PORT) == DSP_READY)
  962.   {
  963.     outp(IOBasePort + DSP_WRITE_PORT, DSP_VERSION);
  964.     while ((inp(IOBasePort + DSP_DATA_AVAIL) & 0x80) == 0);
  965.     DSP_Ver = inp(IOBasePort + DSP_READ_PORT);
  966.     inp(IOBasePort + DSP_READ_PORT);
  967.     return(SUCCESS);
  968.   }
  969.  
  970.   return(FAIL);
  971.  
  972. }
  973.  
  974.  
  975.  
  976. /**************************************************************************
  977. *
  978. * FUNCTION: SetMixer()
  979. *
  980. * DESCRIPTION: Self explanatory
  981. *
  982. **************************************************************************/
  983. void SetMixer(void)
  984. {
  985.   outp(Base + MIXER_ADDR, (int) MIC_VOLUME);
  986.   outp(Base + MIXER_DATA, (int) 0x00);
  987.  
  988.   outp(Base + MIXER_ADDR, (int) VOICE_VOLUME);
  989.   outp(Base + MIXER_DATA, (int) 0xFF);
  990.  
  991.   outp(Base + MIXER_ADDR, (int) MASTER_VOLUME);
  992.   outp(Base + MIXER_DATA, (int) 0xFF);
  993.  
  994.   return;
  995. }
  996.